// SPA_Lexical.cpp :	Initialization of lexical tokens and grammar. Implementation of function prototypes for SPA_Lexical.
// Author: Heng Belson
//
#include "SPA_Lexical.h"
#include <iostream>
#include <fstream>
#include <boost/algorithm/string.hpp>

using namespace std;
using namespace boost;
using namespace boost::xpressive;

/******************************/
// Global Declarations		   
/******************************************************************************************************************/
COLLECTION		proc_names;
STRING			proc_name, proc_body;
COLLECTION		statement_list_block;
STATEMENT_TYPE	statement_type;
STRING			call_proc_name;
STRING			while_condition, while_body;
STRING			if_condition, then_part, else_part;
STRING			assign_left_var, assign_expr, original_expr;
OP_TYPE			operation_type;
COLLECTION		operand_list;

//////////////////////////////////////////////////////////////////
struct Block {
	INTEGER startPos;
	STRING	value;
};

class CompareStartPos {
public:
	BOOLEAN operator() (const Block& b1, const Block& b2) const {
		return (b1.startPos > b2.startPos);
	}
};
//////////////////////////////////////////////////////////////////

STRING		buffer;
STRING		matched_result;

INTEGER		proc_id;
SQUEUE		proc_list;

Block		block;
BCONTAINER	block_container;
/******************************************************************************************************************/

SPA_Lexical::SPA_Lexical() {
	T_Name			=	alpha >> *alnum;
	T_Integer		=	+digit;

	T_Proc_Name		=	T_Name;
	T_Var_Name		=	T_Name;
	T_Const_Value	=	T_Integer;

	TK_Procedure	=	"procedure";
	TK_Call			=	"call";
	TK_While		=	"while";
	TK_If			=	"if";
	TK_Then			=	"then";
	TK_Else			=	"else";

	G_Group			=	*space >> '(' >> *space >> by_ref(G_Expression2) >> *space >> ')' >> *space;
	G_Factor		=	G_Group | T_Var_Name | T_Const_Value;
	G_Term			=	G_Factor >> *space >> +('*' >> *space >> G_Factor >> *space) | G_Factor;
	G_Term2			=	G_Term >> *space >> *('*' >> *space >> G_Factor >> *space);
	G_Expression	=	G_Term2 >> *space >> +(('+' >> *space >> G_Term2 >> *space) | ('-' >> *space >> G_Term2 >> *space)) | G_Term2;
	G_Expression2	=	G_Expression >> *space >> *(('+' >> *space >> G_Term2 >> *space) | ('-' >> *space >> G_Term2 >> *space));

	G_Call			=	*space >> TK_Call >> +space >> T_Proc_Name >> *space >> ';';
	G_While			=	*space >> TK_While >> +space >> T_Var_Name >> *space >> '{' >> *space >> by_ref(G_StmtLst) >> *space >> '}';
	G_Then			=	TK_Then >> *space >> '{' >> *space >> by_ref(G_StmtLst) >> *space >> '}';
	G_Else			=	TK_Else >> *space >> '{' >> *space >> by_ref(G_StmtLst) >> *space >> '}'; 
	G_If			=	*space >> TK_If >> +space >> T_Var_Name >> +space >> G_Then >> *space >> G_Else;
	G_Assign		=	*space >> T_Var_Name >> *space >> '=' >> *space >> G_Expression2 >> *space >> ';';
	G_Stmt			=	G_Call | G_While | G_If | G_Assign;
	G_StmtLst		=	+G_Stmt;		
	G_Procedure		=	*space >> TK_Procedure >> +space >> T_Proc_Name >> *space >> '{' >> *space >> G_StmtLst >> *space >> '}';
	G_Program		=	+G_Procedure;
}

/******************************/
// Lexical Scanner
/******************************************************************************************************************/
void SPA_Lexical::scanner(STRING fileName) {
	INTEGER number_of_open_brace = 0, number_of_close_brace = 0;
	COLLECTION proc_names, call_proc_names;
	COLLECTION tmp;
	STRING line("");
	ifstream in(fileName.c_str());
	
	if (!in.is_open()) 
	{ 
		cerr << "Unable to open file: " << fileName << endl; system("PAUSE"); exit(-1); 
	}

	while (getline(in, line)) 
	{
		find_all(tmp, line, "{");
		number_of_open_brace += tmp.size();
		find_all(tmp, line, "}");
		number_of_close_brace += tmp.size();

		if ((number_of_open_brace != 0) && (number_of_open_brace == number_of_close_brace)) 
		{
			number_of_open_brace = 0; number_of_close_brace = 0;
			buffer.append(line + " ");
			trim(buffer);

			if (!manualMatch(buffer, MATCH_Procedure)) 
			{ 
				cerr << "Invalid SIMPLE syntax!\n" << endl; system("PAUSE"); exit(-1); 
			}
			
			analyze(CONSTRUCT_Procedure);

			//////////////////////////////////////////
			// Check if procedure of same name exist
			//////////////////////////////////////////
			if (hasProcedure(proc_names, getProcName())) 
			{
				cerr << "Invalid SIMPLE syntax!\n" << endl; 
				cerr << "-> Same Procedure Name : " << getProcName() << "\n" << endl;
				system("PAUSE"); exit(-1);
			}
			proc_names.push_back(getProcName());
			//////////////////////////////////////////

			//////////////////////////////////////////
			// Store all call statements
			//////////////////////////////////////////
			STRING tmp = buffer;
			if (manualMatch(tmp, MATCH_Statement_List)) 
			{
				doStatementList();
				COLLECTION stmts = getStmtLstBlock();
				for (INTEGER i = 0; i < (INTEGER) stmts.size(); i++) 
				{
					STRING tmp = stmts[i];
					while (contains(tmp, TK_Call))
					{
						INTEGER start	= tmp.find(TK_Call);
						INTEGER end		= start;
						for (; end < (INTEGER) tmp.length(); end++)
							if (tmp[end] == ';')
								break;
						STRING callStmt = tmp.substr(start, end+1-start);
						tmp.erase(0, end+1);
						if (!match(callStmt, G_Call))
							break;
						analyze(CONSTRUCT_Statement);
						//////////////////////////////////////////
						// Check if recursive calls
						//////////////////////////////////////////
						if (getProcName() == getCall()) 
						{
							cerr << "Invalid SIMPLE syntax!\n" << endl; 
							cerr << "-> Recursive call : " << getProcName() << "\n" << endl;
							system("PAUSE"); exit(-1);
						}
						//////////////////////////////////////////
						call_proc_names.push_back(getCall());
					}
				}
			}
			//////////////////////////////////////////

			proc_list.push(buffer);
			buffer.clear();
		} else buffer.append(line + " ");
	}

	//////////////////////////////////////////
	// Check matching brackets
	//////////////////////////////////////////
	if ((number_of_open_brace != number_of_close_brace)) 
	{
		cerr << "Invalid SIMPLE syntax!\n" << endl; system("PAUSE"); exit(-1); 
	}
	//////////////////////////////////////////

	//////////////////////////////////////////
	// Check call to non-existing procedures
	//////////////////////////////////////////
	for (INTEGER i = 0; i < (INTEGER) call_proc_names.size(); i++) 
	{
		if (!isValidCall(proc_names, call_proc_names[i])) 
		{
			cerr << "Invalid SIMPLE syntax!\n" << endl; 
			cerr << "-> Call to non-existing procedure : " << call_proc_names[i] << "\n" << endl; 
			system("PAUSE"); exit(-1);
		}
	}
	//////////////////////////////////////////
};
/******************************************************************************************************************/

/******************************/
// Lexical Match
/******************************************************************************************************************/
BOOLEAN SPA_Lexical::match(STRING line, LEXICAL lex) {
	MATCHED what;
	BOOLEAN matched_status = false;
	
	if (contains(line, TK_Procedure))
		return manualMatch(line, MATCH_Procedure);

	try 
	{
		matched_status = regex_search(line, what, lex);
		matched_result.clear();
	
		if (matched_status)
			matched_result = what[0];

		return matched_status;
	}
	catch (boost::exception &ex) 
	{ 
		return manualMatch(line, MATCH_Statement_List);
		//cerr << "Invalid SIMPLE syntax!\n" << endl; 
		//cerr << "-> The length of procedure is too long. Please adopt modularity in your program.\n" << endl;
		//system("PAUSE"); exit(-1); 
	}
}
/******************************************************************************************************************/

/******************************/
// Lexical Analyzer
/******************************************************************************************************************/
void SPA_Lexical::analyze(CONSTRUCT_TYPE constructType) {
	BOOLEAN errorFlag = false;

	switch (constructType) 
	{
	case CONSTRUCT_Procedure: 
		errorFlag = doProcedure(); 
		break;
	case CONSTRUCT_Statement_List: 
		errorFlag = doStatementList();
		break;
	case CONSTRUCT_Statement:
		errorFlag = doStatement();
		break;
	case CONSTRUCT_Expression:
		errorFlag = doExpression();
		break;
	}

	if (errorFlag) { cerr << "Invalid SIMPLE syntax!" << endl; system("PAUSE"); exit(-1); }
}
/******************************************************************************************************************/

BOOLEAN SPA_Lexical::manualMatch(STRING line, MATCH_TYPE matchType) {
	STRING token_key("");
	STRING original = line;
	INTEGER prev = 0, openBrace = 0, closeBrace = 0;
	trim(line);

	switch (matchType)
	{
	case MATCH_Procedure:
		{
			for (INTEGER i = 0; line[i] != ' '; i++) 
				token_key += line[i];
			if (token_key == TK_Procedure)
			{
				line.erase(0, TK_Procedure.length());
				trim(line);
				STRING proc_name("");
				for (INTEGER i = 0; line[i] != '{'; i++) 
					proc_name += line[i];

				if (match(proc_name, T_Proc_Name))
				{
					matched_result = original;
					return true;
				}
			}
			break;
		}
	case MATCH_Statement_List:
		{
			line.erase(0, line.find_first_of("{"));
			trim(line);
			original = line;
			for (INTEGER i = 0; i < (INTEGER) line.length(); i++) 
			{
				if (line[i] == '{')
					openBrace++;
				if (line[i] == '}')
					closeBrace++;
			}

			if (openBrace != closeBrace)
				return false;

			erase_first(line,"{"); erase_last(line,"}");
			trim(line);
			for (INTEGER i = 0; i < (INTEGER) line.length(); i++) 
			{
				if (line[i] == '{')
				{
					STRING tmp = line;
					INTEGER k = 0;
					tmp.erase(0, i);
					for (INTEGER j = i; j < (INTEGER) line.length(); j++)
					{
						switch (line[j])
						{
						case '{':
							k++;
							break;
						case '}':
							k--;
							if (k == 0) 
							{
								i = j;
								j = line.length();
							}
							break;
						default:
							continue;
							break;
						}
					}
					STRING stmtLst_definition = line.substr(prev, i+1-prev);
					if (!manualMatch(stmtLst_definition, MATCH_Statement_List)) 
						return false;
					prev = i+1;
				}
				if (line[i] != ';') 
					continue;
				STRING stmt_definition = line.substr(prev, i+1-prev);
				if (!match(stmt_definition, G_Stmt))
					return false;
				prev = i+1;
			}

			matched_result = original;
			return true;
			break;
		}
	}
	return false;
}

BOOLEAN SPA_Lexical::isReducible(STRING expression) {
	return (
		contains(expression, "*") 
		|| 
		contains(expression, "+") 
		|| 
		contains(expression, "-") 
		|| 
		contains(expression, "(") 
		|| 
		contains(expression, ")")
		);
};

BOOLEAN SPA_Lexical::isOperator(char c) {
	return (
		c == '*' 
		|| 
		c == '+' 
		|| 
		c == '-' 
		|| 
		c == '(' 
		|| 
		c == ')'
		);
}

BOOLEAN SPA_Lexical::isValidCall(COLLECTION procList, STRING procName) {
	COLLECTION::iterator it = find(procList.begin(), procList.end(), procName);
	return ((it == procList.end()) ? false : true);
}

BOOLEAN SPA_Lexical::hasProcedure(COLLECTION procList, STRING procName) {
	COLLECTION::iterator it = find(procList.begin(), procList.end(), procName);
	return ((it == procList.end()) ? false : true);
}

STRING SPA_Lexical::evaluateVarName(STRING line) {
	STRING varName("");
	if (match(line, T_Var_Name))
		varName = getMatchedResult();

	if (varName.empty() 
		|| 
		varName == TK_Procedure 
		|| 
		varName == TK_Call 
		|| 
		varName == TK_While 
		|| 
		varName == TK_If 
		|| 
		varName == TK_Then 
		|| 
		varName == TK_Else
		) 
	{
		cerr << "Invalid SIMPLE syntax!\n" << endl; 
		cerr << "-> Restricted Variable Name : " << varName << "\n" << endl; 
		system("PAUSE"); exit(-1);
	}
	return varName;
}

/***************************************/
// Do Methods
/***************************************************************************************************************************/
BOOLEAN SPA_Lexical::doProcedure() {
	STRING name, body;
	STRING tmp = getMatchedResult();
	
	try 
	{
		erase_first(tmp, TK_Procedure);
		for (INTEGER i = 0; tmp[i] != '{'; i++) 
			name += tmp[i];

		name = evaluateVarName(name);

		if(!manualMatch(tmp, MATCH_Statement_List))
			return true;

		body = getMatchedResult();
	} 
	catch (boost::exception &ex) { cerr << &ex << endl; return true; }

	trim(name); trim(body);

	setProcName(name);
	setProcBody(body);

	return false;
}

BOOLEAN SPA_Lexical::doStatementList() {
	STRING tmp = getMatchedResult();
	COLLECTION stmt;

	try 
	{
		trim(tmp);
		if (tmp[0] == '{')
		{
			erase_first(tmp,"{"); 
			erase_last(tmp,"}");
			trim(tmp);
		}

		while (match(tmp, G_Stmt)) 
		{
			STRING s = getMatchedResult();
			trim(s); 
			stmt.push_back(s);
			tmp.erase(0, s.length());
			trim(tmp);
		}
		setStmtLstBlock(stmt);
	} catch (boost::exception &ex) { cerr << "Error " << &ex << endl; return true; }
	return false;
}

BOOLEAN SPA_Lexical::doStatement() {
	STRING tmp = getMatchedResult();

	try 
	{
		if		(match(tmp, G_While))	return doCheck(false, tmp);
		else if (match(tmp, G_If))		return doCheck(false, tmp);
		else if (match(tmp, G_Assign))	return doAssign(tmp);
		else if	(match(tmp, G_Call))	return doCall(tmp);
		else	{ cerr << "Unknown statement type!" << endl; system("PAUSE"); exit(-1); }
	} catch (boost::exception &ex) { cerr << "Error " << &ex << endl; return true; }
}

BOOLEAN SPA_Lexical::doExpression() {
	STRING expr	= getMatchedResult();
	stack<STRING> operandStack;	stack<STRING> operatorStack;
	STRING tmp;
	STRING op, operand1, operand2;
	INTEGER precedence;

	erase_all(expr, " ");

	try 
	{
		while (!expr.empty()) 
		{
			if (!isOperator(expr[0])) // var or constant
			{
				if (!isReducible(expr)) 
				{
					operandStack.push(expr);
					expr.clear();
				} 
				else 
				{
					INTEGER i = 0; tmp.clear();
					while (!isOperator(expr[i])) 
					{
						tmp += expr[i];
						i++;
					}
					operandStack.push(tmp);
					expr.erase(0, i);
				}
			}
			else // operator
			{	
				precedence = (operatorStack.empty()) ? 0 : getOperatorPrecedence(operatorStack.top()[0]);
				tmp = expr[0];
					
				switch (tmp[0]) 
				{
				case '(':
					operatorStack.push(tmp);
					break;
				case ')':
					while (op != "(") 
					{
						op = operatorStack.top();

						operand2 = operandStack.top();
						operandStack.pop();

						operand1 = operandStack.top();
						operandStack.pop();

						operandStack.push(op + "[" + operand1 + "," + operand2 + "]");
						operatorStack.pop();

						op = operatorStack.top();
					}
					operatorStack.pop();
					op.clear();
					break;
				default:
					if (getOperatorPrecedence(tmp[0]) > precedence)
						operatorStack.push(tmp);
					else
					{
						op = operatorStack.top();

						operand2 = operandStack.top();
						operandStack.pop();

						operand1 = operandStack.top();
						operandStack.pop();

						operandStack.push(op + "[" + operand1 + "," + operand2 + "]");
						operatorStack.pop();

						precedence = (operatorStack.empty()) ? 0 : getOperatorPrecedence(operatorStack.top()[0]);
						if (getOperatorPrecedence(tmp[0]) >= precedence) operatorStack.push(tmp);
					}
					break;
				}
				expr.erase(0,1);
			}
		} // end while
			
		while (!operatorStack.empty()) 
		{
			op	= operatorStack.top();

			operand2 = operandStack.top();
			operandStack.pop();

			operand1 = operandStack.top();
			operandStack.pop();

			operandStack.push(op + "[" + operand1 + "," + operand2 + "]");
			operatorStack.pop();
		}
		setAssignExpr(operandStack.top());
	} catch (boost::exception &ex) { cerr << "Error " << &ex << endl; return true; }
	return false;
}

BOOLEAN SPA_Lexical::doCheck(BOOLEAN forContainer, STRING line) {
	INTEGER ifPos, whilePos;

	ifPos		= line.find(TK_If);
	whilePos	= line.find(TK_While);

	if		(ifPos < 0)			return (forContainer ? doWhileContainer(line) : doWhile(line));
	else if (whilePos < 0)		return (forContainer ? doIfContainer(line) : doIf(line));
	else if (ifPos < whilePos)	return (forContainer ? doIfContainer(line) : doIf(line)); 
	else						return (forContainer ? doWhileContainer(line) : doWhile(line));
}

BOOLEAN SPA_Lexical::doIfContainer(STRING line) {
	STRING newtmp = line;
	STRING ifBlock;

	INTEGER startPos = 0, endPos = 0, foundPos;

	while (contains(newtmp, TK_If)) 
	{ 
		/////////////////////////////////////////////////////////////	
		if (match(newtmp, G_If)) 
		{
			ifBlock		=	getMatchedResult(); trim(ifBlock);
			foundPos	=	newtmp.find(TK_If);
			startPos	+=	foundPos;
			endPos		=	foundPos + ifBlock.length();
		} else return true;
		/////////////////////////////////////////////////////////////

		/////////////////////////////////////////////////////////////
		block.startPos	=	startPos;
		block.value		=	ifBlock;
		block_container.push(block);
		/////////////////////////////////////////////////////////////

		startPos		+=	endPos;
		newtmp			=	newtmp.substr(endPos, newtmp.length()-endPos);
	}

	matched_result = line;
	return false;
}

BOOLEAN SPA_Lexical::doWhileContainer(STRING line) {
	STRING newtmp = line;
	STRING whileBlock;

	INTEGER startPos = 0, endPos = 0, foundPos;

	while (contains(newtmp, TK_While)) 
	{ 
		/////////////////////////////////////////////////////////////
		if (match(newtmp, G_While)) 
		{
			whileBlock	=	getMatchedResult(); trim(whileBlock);
			foundPos	=	newtmp.find(TK_While);
			startPos	=	foundPos;
			endPos		=	foundPos + whileBlock.length();
		} else return true;
		/////////////////////////////////////////////////////////////

		/////////////////////////////////////////////////////////////
		block.startPos	=	startPos;
		block.value		=	whileBlock;
		block_container.push(block);
		/////////////////////////////////////////////////////////////

		startPos		+=	endPos;
		newtmp			=	newtmp.substr(endPos, newtmp.length()-endPos);
	}

	matched_result = line;
	return false;
}

BOOLEAN SPA_Lexical::doCall(STRING line) {
	STRING name;
	setStmtType(STATEMENT_Call); 

	try 
	{
		erase_all(line, "call");
		erase_all(line, ";");
		name = evaluateVarName(line);
	} 
	catch (boost::exception &ex) { cerr << "Error " << &ex << endl; return true; }

	setCall(name);

	return false;
}

BOOLEAN SPA_Lexical::doWhile(STRING line) {
	STRING formals, body;
	STRING condition;
	setStmtType(STATEMENT_While);

	try 
	{
		// Condition
		erase_first(line, TK_While);
		condition = evaluateVarName(line);

		// Body
		if (!match(line, G_StmtLst))
			return true;
		body = getMatchedResult();
	} 
	catch (boost::exception &ex) { cerr << "Error " << &ex << endl; return true; }

	trim(condition); trim(body);

	setWhileCondition(condition);
	setWhileBody(body);

	return false;
}

BOOLEAN SPA_Lexical::doIf(STRING line) {
	STRING formals, thenPart, elsePart;
	STRING condition;

	setStmtType(STATEMENT_If);

	try 
	{
		// Condition
		erase_first(line, TK_If);
		condition = evaluateVarName(line);
		line.erase(0, line.find(condition) + condition.length());
		trim(line);

		// Then Part
		if (!match(line, G_Then))
			return true;
		thenPart = getMatchedResult();
		erase_first(thenPart, TK_Then);
		line.erase(0, TK_Then.length() + thenPart.length());
		trim(line);

		// Else Part
		if (!match(line, G_Else))
			return true;
		elsePart = getMatchedResult(); 
		erase_first(elsePart, TK_Else);

		// Extract from then part, else part
		erase_first(thenPart, "{"); erase_last(thenPart, "}"); trim(thenPart);
		erase_first(elsePart, "{"); erase_last(elsePart, "}"); trim(elsePart);
	} 
	catch (boost::exception &ex) { cerr << "Error " << &ex << endl; return true; }

	setIfCondition(condition);
	setIfThenPart(thenPart);
	setIfElsePart(elsePart);

	return false;
}

BOOLEAN SPA_Lexical::doAssign(STRING line) {
	STRING leftVar, expr;
	COLLECTION assign_definition;

	setStmtType(STATEMENT_Assign);
				
	leftVar = evaluateVarName(line);

	split(assign_definition, line, is_any_of("="));
	line = assign_definition[1]; trim(line);

	if (match(line, G_Expression))	
		expr = getMatchedResult();
	else return true;

	trim(leftVar); trim(expr);

	setAssignLeftVar(leftVar);
	analyze(CONSTRUCT_Expression);
	erase_all(expr, " ");
	setOriginalExpr(expr);

	return false;
}
/***************************************************************************************************************************/

STRING SPA_Lexical::getMatchedResult() {
	if (!matched_result.empty()) 
		return matched_result; 
	else { cerr << "Invalid matched result!" << endl; system("PAUSE"); exit(-1); }
}

INTEGER SPA_Lexical::getOperatorPrecedence(const char c) {
	switch (c) {
	case '*': 
		return 2; 
		break;
	case '+': case '-': 
		return 1; 
		break;
	case '(':
		return -1;
		break;
	default: 
		cerr << "Invalid Operator!" << endl; system("PAUSE"); exit(-1); 
		break;
	}
}

/***************************************/
// Get and Set Methods
/***************************************************************************************************************************/
#pragma region Getters and Setters
STRING SPA_Lexical::getNextProcedure() {
	STRING proc_definition = proc_list.front();
	proc_list.pop();
	return proc_definition;
}

INTEGER SPA_Lexical::getTotalProcedures() {
	return proc_list.size();
}

void SPA_Lexical::setProcName(STRING name) {
	proc_name = name;
}

STRING SPA_Lexical::getProcName() {
	return proc_name;
}

void SPA_Lexical::setProcBody(STRING body) {
	proc_body = body;
}

STRING SPA_Lexical::getProcBody() {
	return proc_body;
}

void SPA_Lexical::setStmtLstBlock(COLLECTION stmtLst) {
	statement_list_block = stmtLst;
}

COLLECTION SPA_Lexical::getStmtLstBlock() {
	return statement_list_block;
}

void SPA_Lexical::setStmtType(STATEMENT_TYPE stmtType) {
	statement_type = stmtType;
}

STATEMENT_TYPE SPA_Lexical::getStmtType() {
	return statement_type;
}

void SPA_Lexical::setCall(STRING procName) {
	call_proc_name = procName;
}

STRING SPA_Lexical::getCall() {
	return call_proc_name;
}

void SPA_Lexical::setWhileCondition(STRING condition) {
	while_condition = condition;
}

STRING SPA_Lexical::getWhileCondition() {
	return while_condition;
}

void SPA_Lexical::setWhileBody(STRING body) {
	while_body = body;
}

STRING SPA_Lexical::getWhileBody() {
	return while_body;
}

void SPA_Lexical::setIfCondition(STRING condition) {
	if_condition = condition;
}

STRING SPA_Lexical::getIfCondition() {
	return if_condition;
}

void SPA_Lexical::setIfThenPart(STRING body) {
	then_part = body;
}

STRING SPA_Lexical::getIfThenPart() {
	return then_part;
}

void SPA_Lexical::setIfElsePart(STRING body) {
	else_part = body;
}

STRING SPA_Lexical::getIfElsePart() {
	return else_part;
}

void SPA_Lexical::setAssignLeftVar(STRING leftVar) {
	assign_left_var = leftVar;
}

STRING SPA_Lexical::getAssignLeftVar() {
	return assign_left_var;
}

void SPA_Lexical::setOriginalExpr(STRING expr) {
	original_expr = expr;
}

STRING SPA_Lexical::getOriginalExpr() {
	return original_expr;
}

void SPA_Lexical::setAssignExpr(STRING expr) {
	assign_expr = expr;
}

STRING SPA_Lexical::getAssignExpr() {
	return assign_expr;
}
#pragma endregion
/***************************************************************************************************************************/